/*
*	Copyright (C) 2014  Julio Montes, Mario Carrillo
*	
*	Julio Montes e-mail: imc.coder@gmail.com 
*
*	Mario Carrillo e-mail: mario_90ago@live.com.mx
*
*	BSD 3-Clause License
*/

#include "alliance/include/tool.h"

#include <wx/tokenzr.h>

namespace alliance
{
    const wxString Tool::s_typeInput = _T( "isinput" );
    const wxString Tool::s_typeOutput = _T( "isoutput" );
    const wxString Tool::s_typePattern = _T( "ispattern" );

    Tool::Tool( const wxString &command, const wxString &commandFormat )
        : m_command( command )
        , m_commandFormat( commandFormat )
    {

    }

    Tool::~Tool()
    {

    }

    const wxString &Tool::GetName() const
    {
        return m_command;
    }

    void Tool::Save( sdk::FileConfig *fileConfig )
    {
        const size_t l_position = fileConfig->WriteNewString( _T( "/alliance/tools/tool" ), m_command );
        fileConfig->WriteString( _T( "/alliance/tools/tool" ), m_commandFormat, _T( "format" ), l_position );
        for( size_t i=0; i<m_vectorOptions.size(); ++i )
        {
            fileConfig->WriteAttributesInElement( _T( "/alliance/tools/tool" ), l_position, m_vectorOptions[i].name, m_vectorOptions[i].vectorAttributes );
        }

        for( size_t i=0; i<m_vectorVariables.size(); ++i )
        {
            fileConfig->WriteAttributesInElement( _T( "/alliance/tools/tool" ), l_position, m_vectorVariables[i].name, m_vectorVariables[i].vectorAttributes );
        }

        for( size_t i=0; i<m_vectorOthers.size(); ++i )
        {
            fileConfig->WriteAttributesInElement( _T( "/alliance/tools/tool" ), l_position, m_vectorOthers[i].name, m_vectorOthers[i].vectorAttributes );
        }
    }

    bool Tool::Load( const sdk::vectorElementsString &vectorElements )
    {
        for( size_t i=0; i<vectorElements.size(); ++i )
        {
            if( 0 == vectorElements[i].name.CmpNoCase( _T( "option" ) ) )
            {
                AddOption( vectorElements[i].vectorAttributes );
            }
            else if( 0 == vectorElements[i].name.CmpNoCase( _T( "variable" ) ) )
            {
                AddVariable( vectorElements[i].vectorAttributes );
            }
            else //other
            {
                AddOther( vectorElements[i].name, vectorElements[i].vectorAttributes );
            }
        }

        return true;
    }

    void Tool::AddOption( const sdk::vectorAttributesString &vectorAttributes )
    {
        wxString value;
        wxString additional;

        for( size_t i=0; i<vectorAttributes.size(); ++i )
        {
            const wxString &l_name = vectorAttributes[i].name;
            const wxString &l_value = vectorAttributes[i].value;

            if( 0 == l_name.CmpNoCase( _T( "value" ) ) )
            {
                value = l_value;
            }
            else if( 0 == l_name.CmpNoCase( _T( "additional" ) ) )
            {
                additional = l_value;
            }
        }

        AddOption( value, additional );
    }

    void Tool::AddVariable( const sdk::vectorAttributesString &vectorAttributes )
    {
        wxString name;
        wxString value;

        for( size_t i=0; i<vectorAttributes.size(); ++i )
        {
            const wxString &l_name = vectorAttributes[i].name;
            const wxString &l_value = vectorAttributes[i].value;

            if( 0 == l_name.CmpNoCase( _T( "name" ) ) )
            {
                name = l_value;
            }
            else if( 0 == l_name.CmpNoCase( _T( "value" ) ) )
            {
                value = l_value;
            }
        }

        AddVariable( name, value );
    }

    void Tool::AddOther( const wxString &name, const sdk::vectorAttributesString &vectorAttributes )
    {
        wxString value;
        wxString type;
        for( size_t i=0; i<vectorAttributes.size(); ++i )
        {
            const wxString &l_name = vectorAttributes[i].name;
            const wxString &l_value = vectorAttributes[i].value;

            if( 0 == l_name.CmpNoCase( _T( "value" ) ) )
            {
                value = l_value;
            }
            else if( 0 == l_name.CmpNoCase( _T( "type" ) ) )
            {
                type = l_value;
            }
        }

        AddOther( name, value, type );
    }

    wxString Tool::GetCommandForFile() const
    {
        wxString command;

        wxString variableName;
        wxString variableValue;
        for( size_t i=0; i<m_vectorVariables.size(); ++i )
        {
            const sdk::vectorAttributesString &vAttributes = m_vectorVariables[i].vectorAttributes;
            for( size_t j=0; j<vAttributes.size(); ++j )
            {
                if( vAttributes[j].name == _T( "name" ) )
                {
                    variableName = vAttributes[j].value;
                }
                else if( vAttributes[j].name == _T( "value" ) )
                {
                    variableValue = vAttributes[j].value;
                }
            }

            command += _T( "export " ) + variableName + _T( "=" ) + variableValue + _T( "\n" );
        }

        wxStringTokenizer st( m_commandFormat, wxT( " \n\t\r" ), wxTOKEN_STRTOK );
        while( st.HasMoreTokens() )
        {
            const wxString &token = st.GetNextToken();
            if( 0 == token.CmpNoCase( _T( "command" ) ) )
            {
                command += m_command + _T( " " );
            }
            else if( 0 == token.CmpNoCase( _T( "options" ) ) )
            {
                for( size_t i=0; i<m_vectorOptions.size(); ++i )
                {
                    const sdk::vectorAttributesString &vAttributes = m_vectorOptions[i].vectorAttributes;
                    wxString option;
                    wxString additional;
                    for( size_t j=0; j<vAttributes.size(); ++j )
                    {
                        if( _T( "value" ) == vAttributes[j].name )
                        {
                            option = vAttributes[j].value;
                        }
                        else if( _T( "additional" ) == vAttributes[j].name )
                        {
                            additional = vAttributes[j].value;
                        }
                    }

                    command += option;

                    if( option.EndsWith( _T( "=" ) ) )
                    {
                        command += additional;
                    }
                    else if( !additional.IsEmpty() )
                    {
                        command += _T( " " ) + additional;
                    }

                    command += _T( " " );
                }
            }
            else
            {
                for( size_t i=0; i<m_vectorOthers.size(); ++i )
                {
                    if( m_vectorOthers[i].name == token )
                    {
                        const sdk::vectorAttributesString &vAttributes = m_vectorOthers[i].vectorAttributes;
                        bool hasType = false;
                        wxString value;
                        for( size_t j=0; j<vAttributes.size(); ++j )
                        {
                            if( 0 == vAttributes[j].name.Cmp( _T( "value" ) ) )
                            {
                                value = vAttributes[j].value;
                            }
                            else if( 0 == vAttributes[j].name.Cmp( _T( "type" ) ) &&
                                ( 0 == vAttributes[j].value.Cmp( s_typeOutput ) ||
                                  0 == vAttributes[j].value.Cmp( s_typeInput )  ||
                                  0 == vAttributes[j].value.Cmp( s_typePattern ) ) )
                            {
                                hasType = true;
                            }
                        }

                        if( hasType && value.Find( _T( '.' ) ) != wxNOT_FOUND )
                        {
                            value = value.BeforeLast( _T( '.' ) );
                        }

                        command += value + _T( " " );
                    }
                }
            }
        }

        return command;
    }

    //TODO: test
    wxString Tool::GetFileByType( const wxString &type ) const
    {
        wxString value;
        bool found = false;
        for( size_t i=0; i<m_vectorOthers.size() && !found; ++i )
        {
            const sdk::vectorAttributesString &vAttributes = m_vectorOthers[i].vectorAttributes;
            for( size_t j=0; j<vAttributes.size(); ++j )
            {
                if( 0 == vAttributes[j].name.Cmp( _T( "value" ) ) )
                {
                    value = vAttributes[j].value;
                }
                if( 0 == vAttributes[j].name.Cmp( _T( "type" ) ) &&
                    0 == vAttributes[j].value.Cmp( type ) )
                {
                    found = true;
                }
            }
        }

        return value;
    }

    void Tool::AddVariable( const wxString &name, const wxString &value )
    {
        //TODO: check
        sdk::elementString element;
        element.name = _T( "variable" );

        sdk::attributeString attribute;
        attribute.name = _T( "name" );
        attribute.value = name;
        element.vectorAttributes.push_back( attribute );

        attribute.name = _T( "value" );
        attribute.value = value;
        element.vectorAttributes.push_back( attribute );

        m_vectorVariables.push_back( element );

    }

    void Tool::AddOption( const wxString &value, const wxString &additional  )
    {
        //TODO: check
        sdk::elementString element;
        element.name = _T( "option" );

        sdk::attributeString attribute;
        attribute.name = _T( "value" );
        attribute.value = value;
        element.vectorAttributes.push_back( attribute );

        if( !additional.IsEmpty() )
        {
            attribute.name = _T( "additional" );
            attribute.value = additional;
            element.vectorAttributes.push_back( attribute );
        }

        m_vectorOptions.push_back( element );
    }

    void Tool::AddOther( const wxString &name, const wxString &value, const wxString &type )
    {
        sdk::elementString element;
        element.name = name;

        sdk::attributeString attribute;
        attribute.name = _T( "value" );
        attribute.value = value;
        element.vectorAttributes.push_back( attribute );

        if( !type.IsEmpty() )
        {
            attribute.name = _T( "type" );
            attribute.value = type;
            element.vectorAttributes.push_back( attribute );
        }

        m_vectorOthers.push_back( element );
    }

    const vectorVariables &Tool::GetVariables() const
    {
        return m_vectorVariables;
    }

    const vectorOptions &Tool::GetOptions() const
    {
        return m_vectorOptions;
    }

    const vectorOthers &Tool::GetOthers() const
    {
        return m_vectorOthers;
    }
}
